#pragma once
#include "yzrutil.h"
#include <atomic>

namespace yzrilyzr_lang{
	template<typename T>
	class U_EXPORT_API RefObject{
		protected:
		struct RefControlBLock{
			T * ptr=nullptr;
			std::atomic<long> use_count={0};
		};
		RefControlBLock * refControlBLock=nullptr;

		protected:
		virtual void refDeleteInternal()=0;
		virtual void refCopyFrom(const RefObject & copy)=0;
		virtual T * refCopyOnWriteFrom()=0;

		RefObject()=default;

		inline void refDoCopy(const RefObject & other){
			refControlBLock=other.refControlBLock;
			if(refControlBLock){
				refControlBLock->use_count.fetch_add(1, std::memory_order_relaxed);
			}
			refCopyFrom(other);
		}

		inline void refDoAssignCopy(const RefObject & copy){
			if(this != &copy){
				refDoDestruct();
				refDoCopy(copy);
			}
		}

		inline void refDoConstruct(T * ptr){
			refControlBLock=new RefControlBLock();
			refControlBLock->use_count=1;
			refControlBLock->ptr=ptr;
		}
		inline void refDoDestruct(){
			if(refControlBLock){
				long count=refControlBLock->use_count.fetch_sub(1, std::memory_order_acq_rel);
				if(count == 1){
					delete refControlBLock;
					refControlBLock=nullptr;
					refDeleteInternal();
				}
			}
		}
		inline void refDoCopyOnWrite(){
			if(refControlBLock->use_count > 1){
				T * newData=refCopyOnWriteFrom();
				refDoDestruct();
				refDoConstruct(newData);
			}
		}
	};
}